/*
 *  Copyright 2002 by Texas Instruments Incorporated.
 *  All rights reserved. Property of Texas Instruments Incorporated.
 *  Restricted rights to use, duplicate or disclose this code are
 *  granted through contract.
 *  
 */
/*
 *  ======== thrProcess.c ========
 *  This file contains the main processing thread.
 *  A captured and preprocessed QCIF image is expected from the
 *  capture thread. Then the image will be sent to the 2 "live"
 *  and 2 "diff" channels for processing.
 */
 
// DSP/BIOS includes
#include <std.h>

#include <sts.h>          
#include <string.h>

// DSP/BIOS includes
#include <tsk.h>

// CSL modules
#include <csl_dat.h>
#include <csl_cache.h>

// RF5 module includes
#include <chan.h>
#include <icell.h>
#include <scom.h>
#include <icc_linear.h>
#include <utl.h>

// cell includes
#include "diff/cellDiff.h"
#include "rotate/cellRotate.h"

// application includes
#include "appResources.h"   // application-wide common info

// Thread include
#include "thrProcess.h"

#pragma DATA_SECTION(ybuffCap,       ".EXTPROCBUFF");
#pragma DATA_SECTION(crbuffCap,      ".EXTPROCBUFF");
#pragma DATA_SECTION(cbbuffCap,      ".EXTPROCBUFF");
#pragma DATA_SECTION(ybuffDis,       ".EXTPROCBUFF");
#pragma DATA_SECTION(crbuffDis,      ".EXTPROCBUFF");
#pragma DATA_SECTION(cbbuffDis,      ".EXTPROCBUFF");
#pragma DATA_SECTION(ybuff,          ".EXTPROCBUFF");
#pragma DATA_SECTION(crbuff,         ".EXTPROCBUFF");
#pragma DATA_SECTION(cbbuff,         ".EXTPROCBUFF");
#pragma DATA_ALIGN(ybuffCap,        MEMALIGN);
#pragma DATA_ALIGN(crbuffCap,       MEMALIGN);
#pragma DATA_ALIGN(cbbuffCap,       MEMALIGN);
#pragma DATA_ALIGN(ybuffDis,        MEMALIGN);
#pragma DATA_ALIGN(crbuffDis,       MEMALIGN);
#pragma DATA_ALIGN(cbbuffDis,       MEMALIGN);
#pragma DATA_ALIGN(ybuff,           MEMALIGN);
#pragma DATA_ALIGN(cbbuff,          MEMALIGN);
#pragma DATA_ALIGN(crbuff,          MEMALIGN);

//Buffers for cells of DIFF
#pragma DATA_SECTION(intYBuf,  ".INTPROCBUFF");
#pragma DATA_SECTION(intCrBuf, ".INTPROCBUFF");
#pragma DATA_SECTION(intCbBuf, ".INTPROCBUFF");
#pragma DATA_SECTION(prevY, ".EXTPROCBUFF");
#pragma DATA_SECTION(prevCr, ".EXTPROCBUFF");
#pragma DATA_SECTION(prevCb, ".EXTPROCBUFF");
#pragma DATA_ALIGN(intYBuf,  MEMALIGN);
#pragma DATA_ALIGN(intCrBuf, MEMALIGN);
#pragma DATA_ALIGN(intCbBuf, MEMALIGN);
#pragma DATA_ALIGN(prevY, MEMALIGN);
#pragma DATA_ALIGN(prevCr, MEMALIGN);
#pragma DATA_ALIGN(prevCb, MEMALIGN);

// Static intermediate processing buffers used in cellDiff and cellRotate
static Char intYBuf[DIFF_Y_BUFSIZE];
static Char intCrBuf[DIFF_CR_BUFSIZE];
static Char intCbBuf[DIFF_CB_BUFSIZE];
static Char prevY[PROCF_SIZE_IN_PIXELS];
static Char prevCr[PROCF_SIZE_IN_PIXELS >> 2];
static Char prevCb[PROCF_SIZE_IN_PIXELS >> 2];

/*
 *  Thread process object which encapsulates the state information 
 *  of the thread.
 */ 
ThrProcess thrProcess;


// Buffers for ICC
static Char ybuff [ PROCF_SIZE_IN_PIXELS ];
static Char crbuff[ PROCF_SIZE_IN_PIXELS >> 2 ];
static Char cbbuff[ PROCF_SIZE_IN_PIXELS >> 2 ];
static Char *bufYCRCB[3] = {ybuff, crbuff, cbbuff};

// Buffers for SCOM
static Char ybuffCap [ PROCF_SIZE_IN_PIXELS ];
static Char crbuffCap[ PROCF_SIZE_IN_PIXELS >> 2 ];
static Char cbbuffCap[ PROCF_SIZE_IN_PIXELS >> 2 ];

static Char ybuffDis [ OPF_SIZE_IN_PIXELS ];
static Char crbuffDis[ OPF_SIZE_IN_PIXELS >> 2 ];
static Char cbbuffDis[ OPF_SIZE_IN_PIXELS >> 2 ];

static SCOM_Handle   scomReceiveFromCapture;
static SCOM_Handle   scomSendToCapture;
static SCOM_Handle   scomReceiveFromDisplay;
static SCOM_Handle   scomSendToDisplay;


// Local function prototypes
static Void setParamsAndStartChannels( Bool doChannelOpen );
static Void checkMsg();


/*
 *  ======== thrProcessInit ========
 *
 */
Void thrProcessInit()
{
    Int i;

    // create named SCOM queues for receiving messages from other tasks 
    scomReceiveFromCapture = SCOM_create( "scomToProcessFromCapture", 
                                          &SCOM_ATTRS );
    scomReceiveFromDisplay = SCOM_create( "scomToProcessFromDisplay", 
                                          &SCOM_ATTRS );
  
    UTL_assert( scomReceiveFromCapture != NULL);
    UTL_assert( scomReceiveFromDisplay != NULL);
    
    //Set up the diff cell's env.
    for(i = 0; i < (NUMDIFFCHANS + NUMCOMBOCHANS); i++) {
	   thrProcess.diffEnv[i].intYBuf   = intYBuf;
	   thrProcess.diffEnv[i].intCrBuf  = intCrBuf;
	   thrProcess.diffEnv[i].intCbBuf  = intCbBuf;
	   thrProcess.diffEnv[i].prevY     = prevY;
	   thrProcess.diffEnv[i].prevCr    = prevCr;
	   thrProcess.diffEnv[i].prevCb    = prevCb;
	   thrProcess.diffEnv[i].yBufSize  = DIFF_Y_BUFSIZE;
	   thrProcess.diffEnv[i].crBufSize = DIFF_CR_BUFSIZE;
	   thrProcess.diffEnv[i].cbBufSize = DIFF_CB_BUFSIZE;
	   thrProcess.diffEnv[i].numBlocks = DIFF_NUMBLOCKS;        
    }
    
    //Set up the rotate cell's env
    for(i = 0; i < (NUMROTATECHANS + NUMCOMBOCHANS); i++)
    {
    	thrProcess.rotateEnv[i].intYBuf = intYBuf;
    	thrProcess.rotateEnv[i].intCrBuf = intCrBuf;
    	thrProcess.rotateEnv[i].intCbBuf = intCbBuf;
    	thrProcess.rotateEnv[i].yBufSize = ROTATE_Y_BUFSIZE;
    	thrProcess.rotateEnv[i].crBufSize = ROTATE_CR_BUFSIZE;
    	thrProcess.rotateEnv[i].cbBufSize = ROTATE_CB_BUFSIZE;
    	thrProcess.rotateEnv[i].numBlocks = ROTATE_NUMBLOCKS;
    }
    
    //Allocate appropriate addresses for SCOM buffers
    thrProcess.scombufCap.bufYCRCB[Y] = ybuffCap;
    thrProcess.scombufCap.bufYCRCB[CR] = crbuffCap;
    thrProcess.scombufCap.bufYCRCB[CB] = cbbuffCap;
    
    thrProcess.scombufDisp.bufYCRCB[Y] = ybuffDis;
    thrProcess.scombufDisp.bufYCRCB[CR] = crbuffDis;
    thrProcess.scombufDisp.bufYCRCB[CB] = cbbuffDis;
    
    setParamsAndStartChannels( FALSE );
}


/*
 *  ======== thrProcessStartup ========
 *
 */
Void thrProcessStartup()
{
    setParamsAndStartChannels( TRUE );
}


/*
 *  ======== setParamsAndStartChannels ========
 *
 */
static Void setParamsAndStartChannels( Bool doChannelOpen ) 
{
    IDIFF_Params diffParams;
    IROTATE_Params rotateParams;
    ICC_Handle inputIcc;
    ICC_Handle outputIcc;
    Uns chanNum;
    ICELL_Handle cell;
    Bool rc;

    // Set up params for all XDAIS algorithms
    rotateParams			= IROTATE_PARAMS;
    diffParams              = IDIFF_PARAMS;

    if (doChannelOpen == FALSE) {
    
        /* Setup a default cell used to initialize the actual cells */
        ICELL_Obj   defaultCell = ICELL_DEFAULT;
            
        // Create and assign the linear ICC objects. Then register each cell.        

        // -----------------------
        // Pass-thru Channels 
        // -----------------------
        
        // Pass-thru channel does not have any cells, so it needs no initialization

        // -----------------------
        // Difference Channels 
        // -----------------------
        
        for (chanNum = 0; chanNum < NUMDIFFCHANS; chanNum++) {
        
        
            /*
             *  cell 0 - DIFF: create an input and output linear ICC.
             *  The address to the input ICC will be set in the thrProcessRun()
             *  function via ICC_setBuf().
             */
        
            cell = &thrProcess.diffCells[ chanNum * CHDIFFNUMCELLS ];
            *cell                = defaultCell;
            cell->name           = "DIFF";            
            cell->cellFxns       = &DIFF_CELLFXNS;
            cell->cellEnv        = (Ptr *)&thrProcess.diffEnv[chanNum];
            cell->algFxns        = (IALG_Fxns *)&DIFF_IDIFF;
            cell->algParams      = (IALG_Params *)&diffParams;
            cell->scrBucketIndex = VIDEOPROCSCRBUCKET;
                    
            inputIcc = (ICC_Handle)ICC_linearCreate( NULL, 0);
            UTL_assert( inputIcc != NULL);
			
            outputIcc = (ICC_Handle)ICC_linearCreate( &thrProcess.OutputBuff, 
                         sizeof(thrProcess.OutputBuff));
                         
            UTL_assert( outputIcc != NULL);
                                
            rc = CHAN_regCell ( cell, &inputIcc, 1, &outputIcc, 1 );

        }
        
        // -----------------------
        // Rotate Channels 
        // -----------------------
        
        for (chanNum = 0; chanNum < NUMROTATECHANS; chanNum++) {
        
            /*
             *  cell 0 - ROTATE: create an input and output linear ICC.
             *  The address to the input ICC will be set in the thrProcessRun()
             *  function via ICC_setBuf().
             */
            cell = &thrProcess.rotateCells[ chanNum * CHROTATENUMCELLS ];
            *cell                = defaultCell;
            cell->name           = "ROTATE";
            cell->cellFxns       = &ROTATE_CELLFXNS;
            cell->cellEnv        = (Ptr *)&thrProcess.rotateEnv[chanNum];
            cell->algFxns        = (IALG_Fxns *)&ROTATE_IROTATE;
            cell->algParams      = (IALG_Params *)&rotateParams;
            cell->scrBucketIndex = VIDEOPROCSCRBUCKET;
                    
            inputIcc = (ICC_Handle)ICC_linearCreate( NULL, 0);
            UTL_assert( inputIcc != NULL);

            outputIcc = (ICC_Handle)ICC_linearCreate( &thrProcess.OutputBuff, 
                         sizeof(thrProcess.OutputBuff));
                         
            UTL_assert( outputIcc != NULL);
                                
            rc = CHAN_regCell ( cell, &inputIcc, 1, &outputIcc, 1 );

        }
        
        // -------------------------------------
        // Combo Channels (DIFF and then ROTATE)
        // -------------------------------------
        
        for (chanNum = 0; chanNum < NUMCOMBOCHANS; chanNum++) {
        
			/*
			 *  cell 0 - DIFF: create an input and output linear ICC.
			 *  The address to the input ICC will be set in the thrProcessRun()
			 *  function via ICC_setBuf().
			 */
            cell = &thrProcess.comboCells[ chanNum * CHCOMBONUMCELLS ];
            *cell                = defaultCell;
            cell->name           = "DIFF";
            cell->cellFxns       = &DIFF_CELLFXNS;
            cell->cellEnv        = (Ptr *)&thrProcess.diffEnv[chanNum + NUMDIFFCHANS];
            cell->algFxns        = (IALG_Fxns *)&DIFF_IDIFF;
            cell->algParams      = (IALG_Params *)&diffParams;
            cell->scrBucketIndex = VIDEOPROCSCRBUCKET;
                    
            inputIcc = (ICC_Handle)ICC_linearCreate( NULL, 0);
            UTL_assert( inputIcc != NULL);

            outputIcc = (ICC_Handle)ICC_linearCreate( bufYCRCB, 
                         sizeof(bufYCRCB));
            UTL_assert( outputIcc != NULL);
                                
            rc = CHAN_regCell ( cell, &inputIcc, 1, &outputIcc, 1 );

			/*
		     *  cell 1 - ROTATE: create an input and output linear ICC.
		     */
            cell = &thrProcess.comboCells[ 
                       chanNum * CHCOMBONUMCELLS + CHCOMBOCELLROTATE];
            *cell                = defaultCell;
            cell->name           = "ROTATE";
            cell->cellFxns       = &ROTATE_CELLFXNS;
            cell->cellEnv        = (Ptr *)&thrProcess.rotateEnv[chanNum + NUMROTATECHANS];
            cell->algFxns        = (IALG_Fxns *)&ROTATE_IROTATE;
            cell->algParams      = (IALG_Params *)&rotateParams;
            cell->scrBucketIndex = VIDEOPROCSCRBUCKET;

            inputIcc = (ICC_Handle)ICC_linearCreate(
                               bufYCRCB, sizeof(bufYCRCB));
            UTL_assert( inputIcc != NULL);

            outputIcc = (ICC_Handle)ICC_linearCreate( &thrProcess.OutputBuff, 
                         sizeof(thrProcess.OutputBuff));
                         
            UTL_assert( outputIcc != NULL);
        
            rc = CHAN_regCell ( cell, &inputIcc, 1, &outputIcc, 1 );

	    }
    }
    else {
        // Open the channels
        
        //Open Pass thru chans
        
        //Pass-thru channel does not need to be opened
        
		//Open Diff chans
        for (chanNum = 0; chanNum < NUMDIFFCHANS; chanNum++) {             

            // Set the algorithm's parameters
            thrProcess.diffCells[chanNum * CHDIFFNUMCELLS].algParams = 
                (IALG_Params *)&diffParams;

            // Open the channel            
            UTL_logDebug1("Process: Diff Channel Number: %d", chanNum);
            rc = CHAN_open( &thrProcess.diffChans[chanNum], 
                        &thrProcess.diffCells[chanNum * CHDIFFNUMCELLS],
                        CHDIFFNUMCELLS, NULL );
            UTL_assert( rc == TRUE );
        }
        
        //Open Rotate chans
        for (chanNum = 0; chanNum < NUMROTATECHANS; chanNum++) { 

            // Set the algorithm's parameters
            thrProcess.rotateCells[chanNum * CHROTATENUMCELLS].algParams = 
                (IALG_Params *)&rotateParams;

            // Open the channel            
            UTL_logDebug1("Process: Rotate Channel Number: %d", chanNum);
            rc = CHAN_open( &thrProcess.rotateChans[chanNum], 
                        &thrProcess.rotateCells[chanNum * CHROTATENUMCELLS],
                        CHROTATENUMCELLS, NULL );
            UTL_assert( rc == TRUE );
        }
        
		//Open Combo chans
		for (chanNum = 0; chanNum < NUMCOMBOCHANS; chanNum++) { 
		
		    // Set the algorithm's parameters
		    thrProcess.comboCells[chanNum * CHCOMBONUMCELLS].algParams = 
		        (IALG_Params *)&diffParams;
		    thrProcess.comboCells[
		        chanNum * CHCOMBONUMCELLS + CHCOMBOCELLROTATE].algParams =
		        (IALG_Params *)&rotateParams;
		
		    // Open the channel            
		    UTL_logDebug1("Process: Combo Channel Number: %d", chanNum);
		    rc = CHAN_open( &thrProcess.comboChans[chanNum], 
		                &thrProcess.comboCells[chanNum * CHCOMBONUMCELLS],
		                CHCOMBONUMCELLS, NULL );
		    UTL_assert( rc == TRUE );
		}
    }
}

static Void checkMsg()
{
    CtrlMsg rxMsg;
    Int index;

    // check message in "mbxProc"    
    while( MBX_pend( &mbxProcess, &rxMsg, 0) ) {
        switch (rxMsg.cmd) {
            case MSGNEWREFERENCE:	//setting a new reference frame
            	thrProcess.diffEnv->SetReference = TRUE;
            	break;
            
            case MSGNEWCOLOR:		//change color of unequal pixels
            	for (index = 0; index < (NUMDIFFCHANS + NUMCOMBOCHANS); index++)
            	{
	            	thrProcess.diffEnv[index].yValue = rxMsg.arg1;
	            	thrProcess.diffEnv[index].crValue = rxMsg.arg2 >> 8;
	            	thrProcess.diffEnv[index].cbValue = rxMsg.arg2 % 256;
	            }
	            break;
            default:
                break;
        }
    }
}

/*
 *  ======== thrProcessRun ========
 *
 *  Main function of Process Thread.
 */
Void thrProcessRun() 
{
    CHAN_Handle chan;
    Int prevYId;
    Int prevCrId;
    Int prevCbId;

    UTL_logDebug1("thrProcessRun: task = 0x%x", TSK_self());
    
    // open SCOM queues for sending messages to other tasks
    scomSendToCapture = SCOM_open( "scomCapture" );
    scomSendToDisplay = SCOM_open( "scomDisplay" );
    UTL_assert( scomSendToCapture != NULL);
    UTL_assert( scomSendToDisplay != NULL);
        
    // processed buffers
    memset(ybuff,  0x00, PROCF_SIZE_IN_PIXELS);
    memset(crbuff, 0x80, PROCF_SIZE_IN_PIXELS >> 2);
    memset(cbbuff, 0x80, PROCF_SIZE_IN_PIXELS >> 2);

    //Clear Capture and Display SCOM buffers
    memset(ybuffCap,  0x00, PROCF_SIZE_IN_PIXELS);
    memset(crbuffCap, 0x80, PROCF_SIZE_IN_PIXELS >> 2);
    memset(cbbuffCap, 0x80, PROCF_SIZE_IN_PIXELS >> 2);
    
    memset(ybuffDis,  0x00, OPF_SIZE_IN_PIXELS);
    memset(crbuffDis, 0x80, OPF_SIZE_IN_PIXELS >> 2);
    memset(cbbuffDis, 0x80, OPF_SIZE_IN_PIXELS >> 2);
     
    // put the Rx message on the SCOM queue for Capture thread
    SCOM_putMsg( scomSendToCapture, &thrProcess.scombufCap );
    
    // put the Tx message on the SCOM queue for Display thread
    SCOM_putMsg( scomSendToDisplay, &thrProcess.scombufDisp );

    // Main loop
    while (TRUE) {         
        ScomProcToDisp *scombufDisp;
        ScomCapToProc  *scombufCap;    
        Int chanNum;
        Bool rc;
        
        // check message from the control thread
        checkMsg();
                
        // get the message describing full input buffers from Capture
        scombufCap = SCOM_getMsg(scomReceiveFromCapture, 
            SYS_FOREVER);
        
        // get the message describing empty output buffers from Display
        scombufDisp = SCOM_getMsg(scomReceiveFromDisplay,
            SYS_FOREVER);        
    
    	//Update Reference Frame if necessary
    	if (thrProcess.diffEnv->SetReference == TRUE)
    	{
    	    CACHE_wbInvL2(scombufCap->bufYCRCB[Y], CAPF_SIZE_IN_PIXELS, CACHE_WAIT);
    	    CACHE_wbInvL2(scombufCap->bufYCRCB[CR], CAPF_SIZE_IN_PIXELS>>2, CACHE_WAIT);
    	    CACHE_wbInvL2(scombufCap->bufYCRCB[CB], CAPF_SIZE_IN_PIXELS>>2, CACHE_WAIT);
    	    
    		prevYId = DAT_copy2d(DAT_2D1D, (Void *) scombufCap->bufYCRCB[Y], (Void *) prevY, PROCF_WIDTH, PROCF_HEIGHT, PROCF_WIDTH);
    		prevCrId = DAT_copy2d(DAT_2D1D, (Void *) scombufCap->bufYCRCB[CR], (Void *) prevCr, PROCF_WIDTH>>1, PROCF_HEIGHT>>1, PROCF_WIDTH>>1);
    		prevCbId = DAT_copy2d(DAT_2D1D, (Void *) scombufCap->bufYCRCB[CB], (Void *) prevCb, PROCF_WIDTH>>1, PROCF_HEIGHT>>1, PROCF_WIDTH>>1);

    		CACHE_invL2(prevY, CAPF_SIZE_IN_PIXELS, CACHE_WAIT);
    	    CACHE_invL2(prevCr, CAPF_SIZE_IN_PIXELS>>2, CACHE_WAIT);
    	    CACHE_invL2(prevCb, CAPF_SIZE_IN_PIXELS>>2, CACHE_WAIT);
    	    
    		thrProcess.diffEnv->SetReference = FALSE;
    	}
    	
    	DAT_wait(prevYId);
    	DAT_wait(prevCrId);
    	DAT_wait(prevCbId);
    
        //Execute all passthrough channels
        for (chanNum = 0; chanNum < NUMPASSCHANS; chanNum++) {
            
            //Simply place the buffers from Cap to Dis
            DAT_copy2d(DAT_1D2D, scombufCap->bufYCRCB[Y],scombufDisp->bufYCRCB[Y],PROCF_WIDTH, PROCF_HEIGHT, OPF_WIDTH);
            DAT_copy2d(DAT_1D2D, scombufCap->bufYCRCB[CR],scombufDisp->bufYCRCB[CR],PROCF_WIDTH >> 1, PROCF_HEIGHT >> 1, OPF_WIDTH >> 1);
            prevCbId = DAT_copy2d(DAT_1D2D, scombufCap->bufYCRCB[CB],scombufDisp->bufYCRCB[CB],PROCF_WIDTH >> 1, PROCF_HEIGHT >> 1, OPF_WIDTH >> 1);
         
          	DAT_wait(prevCbId); 
        }

        //Execute all diff channels
        for (chanNum = 0; chanNum < NUMDIFFCHANS; chanNum++) {
                
            chan = &(thrProcess.diffChans[chanNum]);
            
            // assign the buffers to the ICC objects
            // Redundant with the SCOM queue is single-buffered. Needed when the
            // queue is multiple-buffered.
            ICC_setBuf(chan->cellSet[CHDIFFCELLDIFF].inputIcc[0],
                 scombufCap->bufYCRCB, 0);
                 
            // Assign correct offset values to buffers
			thrProcess.OutputBuff.y = scombufDisp->bufYCRCB[Y] + Q2_Y_OFFSET;
			thrProcess.OutputBuff.cr = scombufDisp->bufYCRCB[CR] + Q2_CR_OFFSET;
			thrProcess.OutputBuff.cb = scombufDisp->bufYCRCB[CB] + Q2_CB_OFFSET;
			thrProcess.diffEnv[0].linePitch = OPF_WIDTH;

            ICC_setBuf(chan->cellSet[CHDIFFCELLDIFF].outputIcc[0],
                 &thrProcess.OutputBuff, 0);

            UTL_stsStart( stsExeTimeChDiff );
            rc = CHAN_execute( &thrProcess.diffChans[ chanNum ], NULL );    
            UTL_assert( rc == TRUE );
            UTL_stsStop( stsExeTimeChDiff );
        }
        
        //Execute all rotate channels
        for (chanNum = 0; chanNum < NUMROTATECHANS; chanNum++) {
                
            chan = &(thrProcess.rotateChans[chanNum]);
            
            // assign the buffers to the ICC objects
            // Redundant with the SCOM queue is single-buffered. Needed when the
            // queue is multiple-buffered.
            ICC_setBuf(chan->cellSet[CHROTATECELLROTATE].inputIcc[0],
                 scombufCap->bufYCRCB, 0);
                 
            // Assign correct offset values to buffers
			thrProcess.OutputBuff.y = scombufDisp->bufYCRCB[Y] + Q3_Y_OFFSET;
			thrProcess.OutputBuff.cr = scombufDisp->bufYCRCB[CR] + Q3_CR_OFFSET;
			thrProcess.OutputBuff.cb = scombufDisp->bufYCRCB[CB] + Q3_CB_OFFSET;
			thrProcess.rotateEnv[0].linePitch = OPF_WIDTH;

            ICC_setBuf(chan->cellSet[CHROTATECELLROTATE].outputIcc[0],
                 &thrProcess.OutputBuff, 0);

            UTL_stsStart( stsExeTimeChRotate );
            rc = CHAN_execute( &thrProcess.rotateChans[ chanNum ], NULL );    
            UTL_assert( rc == TRUE );
            UTL_stsStop( stsExeTimeChRotate );
        }
        
		//Execute all combo channels
		for (chanNum = 0; chanNum < NUMCOMBOCHANS; chanNum++) {
		        
		    chan = &(thrProcess.comboChans[chanNum]);
		    
		    // assign the buffers to the ICC objects
		    // Redundant with the SCOM queue is single-buffered. Needed when the
		    // queue is multiple-buffered.
		    ICC_setBuf(chan->cellSet[CHCOMBOCELLDIFF].inputIcc[0],
		         scombufCap->bufYCRCB, 0);
		         
		    // Assign correct offset values to buffers
			thrProcess.OutputBuff.y = scombufDisp->bufYCRCB[Y] + Q4_Y_OFFSET;
			thrProcess.OutputBuff.cr = scombufDisp->bufYCRCB[CR] + Q4_CR_OFFSET;
			thrProcess.OutputBuff.cb = scombufDisp->bufYCRCB[CB] + Q4_CB_OFFSET;
			thrProcess.diffEnv[1].linePitch = PROCF_WIDTH;
			thrProcess.rotateEnv[1].linePitch = OPF_WIDTH;

		    ICC_setBuf(chan->cellSet[CHCOMBOCELLROTATE].outputIcc[0],
		         &thrProcess.OutputBuff, 0);
		
		    UTL_stsStart( stsExeTimeChCombo );
		    rc = CHAN_execute( &thrProcess.comboChans[ chanNum ], NULL );    
		    UTL_assert( rc == TRUE );
		    UTL_stsStop( stsExeTimeChCombo );
		}

        // send the now full buffer to Display
        SCOM_putMsg( scomSendToDisplay, scombufDisp );

        // send the message describing consumed input buffers to Capture
        SCOM_putMsg( scomSendToCapture, scombufCap );
    }
}

